﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once

// from gnuf
#include "GcmpUiDocumentImpl.h"
#include "GnufImpl.h"
// from gcmp
#include "IUiDocumentViewManager.h"
#include "WeakPtr.h"

#ifdef _GNUF_WIP_REFACTOR_UIDOC_UIVIEW_LOGIC_

#pragma warning(push)
#pragma warning(disable: 4996)

namespace gcmp {

    class IDocument;
    class UiViewEvent;
    class UiDocumentEvent;
    class UIDocument;
    class UIView;
    
    namespace impl { class GNUF_IMPL_CLASS(UIDocumentManager); }
    class GCMP_UIDOCUMENTIMPL_EXPORT UIDocumentManager : public gcmp::IUiDocumentViewManager
    {
        DEFINE_CAST_DERIVED(gcmp::UIDocumentManager, gcmp::IUiDocumentViewManager);
        GNUF_IMPL_USE(UIDocumentManager);

    protected:
        explicit UIDocumentManager();

    public:
        virtual ~UIDocumentManager();
        
        ///\return Return the active UIDocument.
        const UIDocument * activeUIDocument() const;
        UIDocument * activeUIDocument();

        ///\return Return the active UIView.
        const UIView * activeUIView() const;
        UIView * activeUIView();

    public:
        // Inherits from gcmp::IUiDocumentViewManager...
        virtual gcmp::IUiDocument * CreateUiDocument(gcmp::IDocument *) override final;
        virtual gcmp::IUiView * GetUiViewByRuntimeId(int uiViewId) override final;
        virtual gcmp::IUiDocument * GetUiDocumentByRuntimeId(int id) final;
        virtual gcmp::IUiDocument * GetUiDocumentByName(const std::wstring & name) final;
        virtual std::vector< gcmp::IUiDocument * > GetAllUiDocuments() override final;
        virtual bool ActivateUiDocument(int uiDocumentId) override final;
        virtual bool ActivateUiDocument(int uiDocumentId, int uiViewId) override final;
        virtual gcmp::IUiView * GetCurrentUiView() override final;
        virtual gcmp::IUiDocument * GetCurrentUiDocument() override final;
        virtual bool IsUiViewVisible(gcmp::IUiView *) const override final;
        virtual bool SetUiViewVisible(gcmp::IUiView *, bool) override final;
        virtual gcmp::IUiViewEvent * GetUiViewEvent() override final;
        virtual gcmp::IUiDocumentEvent * GetUiDocumentEvent() override final;
    };

}

namespace gcmp { namespace impl {
    class UIDocumentFamily;

    class GNUF_IMPL_CLASS(UIDocumentManager) final
    {
        GNUF_IMPL_USED_BY(UIDocumentManager);
    public:
        GNUF_IMPL_CLASS(UIDocumentManager)(UIDocumentManager * pItf);
        ~GNUF_IMPL_CLASS(UIDocumentManager)();

        const UIDocument * uiDocumentById(const int id) const;
        UIDocument * uiDocumentById(const int id);

        const UIDocument * uiDocumentByName(const std::wstring & name) const;
        UIDocument * uiDocumentByName(const std::wstring & name);

        const UIView * uiViewById(const int id) const;
        UIView * uiViewById(const int id);
        
        // Return the active UIDocument.
        const UIDocument * activeUIDocument() const;
        UIDocument * activeUIDocument();
        
        // Return the family.
        const UIDocumentFamily * family() const;
        UIDocumentFamily * family();
        
        // Add an UIDocument.
        UIDocument * addUIDocument(gcmp::IDocument *);

        void travelRecursively(const std::function<bool(const UIDocument *)> & callback) const;
        void travelRecursively(const std::function<bool(UIDocument *)> & callback);
        
        // For switching UIDocument's state.
        bool onPreClosed        (const UIDocument *, const bool wasActive);
        void onPostClosed       (      UIDocument *);
        bool  onPreActivated    (const UIDocument *);
        void onPostActivated    (const UIDocument *);
        bool  onPreDeactivated  (const UIDocument *);
        void onPostDeactivated  (const UIDocument *);

        gcmp::UiViewEvent *     uiViewEvent();
        gcmp::UiDocumentEvent * uiDocumentEvent();

        template <class TObject>
        class Closing {
        public:
            bool   isValid() const { return (nullptr != object() && 0 != m_wasActive); }
            bool    isNull() const { return (nullptr == object() && 0 == m_wasActive); }
            bool wasActive() const { return (m_wasActive > 0); }
            bool operator==(const TObject * pObject) const { return (pObject == object()); }
        protected:
            virtual const TObject * object() const = 0;
            void set(const bool wasActive)
            {
                m_wasActive = (wasActive ? 1 /* active  */ : -1 /* inactive */);
            }
            void reset() { m_wasActive = 0; }
        private:
            std::int8_t m_wasActive = 0; // -1:inactive, 0:unknown, 1:active
        };
        class ClosingUIDocument : public UIDocumentManager::Impl::Closing<UIDocument> {
        public:
            void begin(const UIDocument *, const bool wasActive);
            void   end();
        private:
            friend const UIDocument * UIDocumentManager::activeUIDocument() const;
            virtual const UIDocument * object() const override final;
            gcmp::WeakPtr< UIDocument > m_wpUIDoc;
        };
        class ClosingUIView : public UIDocumentManager::Impl::Closing<UIView> {
        public:
            void begin(const UIView *, const bool wasActive);
            void   end();
            const UIDocument * uiDocument() const;
        private:
            friend const UIView * UIDocumentManager::activeUIView() const;
            virtual const UIView * object() const override final;
            gcmp::WeakPtr< UIView > m_wpUIView;
            gcmp::WeakPtr< UIDocument > m_wpUIDoc;
        };

        const UIDocumentManager::Impl::ClosingUIDocument & closingUIDocument() const { return m_closingUIDocucment; }
        const UIDocumentManager::Impl::ClosingUIView & closingUIView() const { return m_closingUIView; }
        UIDocumentManager::Impl::ClosingUIView & rClosingUIView() { return m_closingUIView; }
        
    private:
        // Remove the UIDocument.
        bool removeUIDocument(UIDocument *);
        bool resetActiveUIDocument();

        struct Active {
            friend bool UIDocumentManager::Impl::onPreActivated(const UIDocument *);
            friend void UIDocumentManager::Impl::onPostActivated(const UIDocument *);
            friend void UIDocumentManager::Impl::onPostDeactivated(const UIDocument *);
            enum EState : std::uint8_t { eNull, ePending, eConfirmed };
            UIDocumentManager::Impl::Active::EState operator()() const { return m_data; }
            bool isNull()      const { return (UIDocumentManager::Impl::Active::eNull      == m_data); }
            bool isPending()   const { return (UIDocumentManager::Impl::Active::ePending   == m_data); }
            bool isConfirmed() const { return (UIDocumentManager::Impl::Active::eConfirmed == m_data); }
        private:
            void operator=(const UIDocumentManager::Impl::Active::EState val) { m_data = val; }
            UIDocumentManager::Impl::Active::EState m_data = UIDocumentManager::Impl::Active::eNull;
        } m_activeUIDocument;
        gcmp::OwnerPtr< UIDocumentFamily > m_opFamily;
        gcmp::OwnerPtr< gcmp::UiViewEvent > m_opUiViewEvent;
        gcmp::OwnerPtr< gcmp::UiDocumentEvent > m_opUiDocumentEvent;
        UIDocumentManager::Impl::ClosingUIDocument m_closingUIDocucment;
        UIDocumentManager::Impl::ClosingUIView m_closingUIView;
    };
} }

#pragma warning(pop)

#endif // !_GNUF_WIP_REFACTOR_UIDOC_UIVIEW_LOGIC_